;;
;; Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
;; DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
;;
;; The Universal Permissive License (UPL), Version 1.0
;;
;; Subject to the condition set forth below, permission is hereby granted to any
;; person obtaining a copy of this software, associated documentation and/or
;; data (collectively the "Software"), free of charge and under any and all
;; copyright rights in the Software, and any and all patent rights owned or
;; freely licensable by each licensor hereunder covering either (i) the
;; unmodified Software as contributed to or provided by such licensor, or (ii)
;; the Larger Works (as defined below), to deal in both
;;
;; (a) the Software, and
;;
;; (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
;; one is included with the Software each a "Larger Work" to which the Software
;; is contributed by such licensors),
;;
;; without restriction, including without limitation the rights to copy, create
;; derivative works of, display, perform, and distribute the Software and make,
;; use, sell, offer for sale, import, export, have made, and have sold the
;; Software and the Larger Work(s), and to sublicense the foregoing rights on
;; either these or other terms.
;;
;; This license is subject to the following condition:
;;
;; The above copyright notice and either this complete permission notice or at a
;; minimum a reference to the UPL must be included in all copies or substantial
;; portions of the Software.
;;
;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
;; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
;; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
;; SOFTWARE.
;;
(module
    (type $empty (func))
    (type $int (func (param i32 i64)))
    (type $float (func (param f32 f64)))
    (type $func (func (param funcref)))
    (type $exc (func (param exnref)))

    (tag $emptyTag (type $empty))
    (tag $intTag (type $int))
    (tag $floatTag (type $float))
    (tag $funcTag (type $func))
    (tag $excTag (type $exc))

    (func $f1 (result i32)
        i32.const 1
    )

    (func $f2 (result i32)
        i32.const 2
    )

    (table $table 2 2 funcref)
    (elem (i32.const 0) $f1 $f2)

    (func $thrower (param i32)
        block (result exnref)
            try_table (catch_ref $emptyTag 0)
                block
                    block
                        block
                            local.get 0
                            i32.const 0
                            i32.ne
                            br_if 0
                            i32.const 13
                            i64.const 42
                            throw $intTag
                        end
                        local.get 0
                        i32.const 1
                        i32.ne
                        br_if 0
                        f32.const 3.14
                        f64.const 9.81
                        throw $floatTag
                    end
                    local.get 0
                    i32.const 2
                    i32.ne
                    br_if 0
                    i32.const 1
                    table.get $table
                    throw $funcTag
                end
                throw $emptyTag
            end
            return
        end
        throw $excTag
    )

    (func (export "_main") (result i32)
        block $invalid
            block (result funcref)
                try_table (catch $funcTag 0)
                    block (result i32 i64)
                        try_table (catch $intTag 0)
                            i32.const 0
                            call $thrower
                            i32.const 1001
                            return
                        end
                        unreachable
                    end
                    i64.const 42
                    i64.ne
                    br_if $invalid
                    i32.const 13
                    i32.ne
                    br_if $invalid
                    block (result f32 f64)
                        try_table (catch $floatTag 0)
                            i32.const 1
                            call $thrower
                            i32.const 1002
                            return
                        end
                        unreachable
                    end
                    f64.const 9.81
                    f64.ne
                    br_if $invalid
                    f32.const 3.14
                    f32.ne
                    br_if $invalid

                    i32.const 2
                    call $thrower
                    i32.const 1003
                    return
                end
                unreachable
            end
            ref.is_null
            br_if $invalid
            block
                try_table (catch $emptyTag 0)
                    block (result exnref)
                        try_table (catch $excTag 0)
                            i32.const 3
                            call $thrower
                            i32.const 1004
                            return
                        end
                        unreachable
                    end
                    throw_ref
                end
            end
            i32.const 1005
            return
        end
        i32.const 1000
    )
)